package cn.nvr.file.conversion.util;

import cn.nvr.file.conversion.enu.FileTypeEnu;
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Slf4j
@Component
public class JacobOffice2PdfUtil {

    private static final int wdFormatPDF = 17;

    private static final int xlTypePDF = 0;

    private static final int ppSaveAsPDF = 32;

    /***
     * 文件转换为pdf
     *
     * @param sourceFile        源文件路径
     * @param fileTypeEnu       源文件类型
     * @param targetFile        目标文件路径
     */
    @Async
    public void convert2PDF(String sourceFile, FileTypeEnu fileTypeEnu, String targetFile) {

        Path sourceFilePath = Paths.get(sourceFile);
        if (Files.notExists(sourceFilePath)) {
            log.error("原始文件文件不存在");
            throw new RuntimeException("原始文件文件不存在");
        }

        switch (fileTypeEnu) {
            case WORD:
            case TXT:
                word2PDF(sourceFile, targetFile);
                break;
            case PPT:
                ppt2PDF(sourceFile, targetFile);
                break;
            case EXCEL:
                ex2PDF(sourceFile, targetFile);
                break;
            case PDF:
                try {
                    Files.copy(sourceFilePath, Paths.get(targetFile));
                } catch (IOException e) {
                    log.error("文件copy失败！异常信息:", e);
                    break;
                }
        }
    }

    /**
     * Word转PDF
     *
     * @param inputFile 源文件
     * @param pdfFile   目标文件
     */
    private void word2PDF(String inputFile, String pdfFile) {

        try {
            long startTime = System.currentTimeMillis();
            ComThread.InitSTA(true);
            // 打开Word应用程序
            ActiveXComponent app = new ActiveXComponent("KWPS.Application");
            log.info("开始转化Word为PDF...");

            // 设置Word不可见
            app.setProperty("Visible", new Variant(false));
            // 禁用宏
            app.setProperty("AutomationSecurity", new Variant(3));
            // 获得Word中所有打开的文档，返回documents对象
            Dispatch docs = app.getProperty("Documents").toDispatch();
            // 调用Documents对象中Open方法打开文档，并返回打开的文档对象Document
            Dispatch doc = Dispatch.call(docs, "Open", inputFile, false, true).toDispatch();

            //调用Document对象的SaveAs方法，将文档保存为pdf格式
            //Dispatch.call(doc, "SaveAs", pdfFile, wdFormatPDF word保存为pdf格式宏，值为17 )
            Dispatch.call(doc, "ExportAsFixedFormat", pdfFile, wdFormatPDF);// word保存为pdf格式宏，值为17

            // 关闭文档
            Dispatch.call(doc, "Close", false);
            // 关闭Word应用程序
            app.invoke("Quit", 0);

            log.info("当前线程:{}, 共计用时:{}", Thread.currentThread().getName(), System.currentTimeMillis() - startTime);
        } finally {
            ComThread.Release();
        }

    }

    /***
     * Excel转化成PDF
     *
     * @param inputFile         输入文件
     * @param pdfFile           输出文件
     */
    private void ex2PDF(String inputFile, String pdfFile) {

        try {
            ComThread.InitSTA(true);
            ActiveXComponent ax = new ActiveXComponent("KWPS.Application");
            log.info("开始转化Excel为PDF...");

            ax.setProperty("Visible", false);
            ax.setProperty("AutomationSecurity", new Variant(3)); // 禁用宏
            Dispatch excels = ax.getProperty("Workbooks").toDispatch();

            Dispatch excel = Dispatch
                    .invoke(excels, "Open", Dispatch.Method,
                            new Object[]{inputFile, new Variant(false), new Variant(false)}, new int[9])
                    .toDispatch();
            // 转换格式
            Dispatch.invoke(excel, "ExportAsFixedFormat", Dispatch.Method, new Object[]{new Variant(0), // PDF格式=0
                    pdfFile, new Variant(xlTypePDF) // 0=标准 (生成的PDF图片不会变模糊) 1=最小文件
                    // (生成的PDF图片糊的一塌糊涂)
            }, new int[1]);

            // 这里放弃使用SaveAs
            /*
             * Dispatch.invoke(excel,"SaveAs",Dispatch.Method,new Object[]{ outFile, new
             * Variant(57), new Variant(false), new Variant(57), new Variant(57), new
             * Variant(false), new Variant(true), new Variant(57), new Variant(true), new
             * Variant(true), new Variant(true) },new int[1]);
             */
            Dispatch.call(excel, "Close", new Variant(false));

            ax.invoke("Quit", new Variant[]{});
        } finally {
            ComThread.Release();
        }
    }

    /**
     * ppt转化成PDF
     *
     * @param inputFile 输入文件
     * @param pdfFile   输出文件
     */
    private void ppt2PDF(String inputFile, String pdfFile) {
        log.info("开始转化PPT为PDF...");
        try {
            ComThread.InitSTA(true);
            ActiveXComponent app = new ActiveXComponent("KWPS.Application");
//            app.setProperty("Visible", false);
            Dispatch ppts = app.getProperty("Presentations").toDispatch();
            Dispatch ppt = Dispatch.call(ppts, "Open", inputFile, true, // ReadOnly
                    // false, // Untitled指定文件是否有标题
                    false// WithWindow指定文件是否可见
            ).toDispatch();
            Dispatch.invoke(ppt, "SaveAs", Dispatch.Method, new Object[]{pdfFile, new Variant(ppSaveAsPDF)}, new int[1]);
            log.info("PPT");
            Dispatch.call(ppt, "Close");

            app.invoke("Quit");
        } finally {
            ComThread.Release();
        }
    }

    // 删除多余的页，并转换为PDF
    public void interceptPPT(String inputFile, String pdfFile) {
        ActiveXComponent app;
        try {
            ComThread.InitSTA(true);
            app = new ActiveXComponent("KWPP.Application");
            ActiveXComponent presentations = app.getPropertyAsComponent("Presentations");
            ActiveXComponent presentation = presentations.invokeGetComponent("Open", new Variant(inputFile),
                    new Variant(false));
            int count = Dispatch.get(presentations, "Count").getInt();
            System.out.println("打开文档数:" + count);
            ActiveXComponent slides = presentation.getPropertyAsComponent("Slides");
            int slidePages = Dispatch.get(slides, "Count").getInt();
            System.out.println("ppt幻灯片总页数:" + slidePages);

            // 总页数的20%取整+1 最多不超过5页
            int target = Math.min((int) (slidePages * 0.5) + 1, 5);
            // 删除指定页数
            while (slidePages > target) {
                // 选中指定页幻灯片
                Dispatch slide = Dispatch.call(presentation, "Slides", slidePages).toDispatch();
                Dispatch.call(slide, "Select");
                Dispatch.call(slide, "Delete");
                slidePages--;
                System.out.println("当前ppt总页数:" + slidePages);
            }
            Dispatch.invoke(presentation, "SaveAs", Dispatch.Method, new Object[]{pdfFile, new Variant(32)},
                    new int[1]);
            Dispatch.call(presentation, "Save");
            Dispatch.call(presentation, "Close");
            app.invoke("Quit");
        } finally {
            ComThread.Release();
        }
    }
}
